package dev.ece.suit.ui;

import java.awt.Adjustable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Vector;

import dev.ece.core.texture.Texture;
import dev.ece.suit.ui.event.ScrollBarListener;
import dev.ece.suit.ui.event.ScrollPaneContentItemsListener;
import dev.ece.util.GLUtils;
import dev.ece.util.lib.IntOffset;
import dev.ece.util.lib.IntRectangle;
import dev.ece.util.lib.Rectangle;
import dev.ece.util.lib.Vector2f;
import dev.ece.util.obj.ObjectCount;
import dev.ece.util.tools.Camera;

public class ScrollPane<T extends ContentItem> extends Component implements ScrollBarListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 3434406618185313459L;

	private ScrollBar horizontalScrollBar;
	
	private ScrollBar verticalScrollBar;
	
	private boolean showHorizontalScrollBar = true;
	
	private boolean showVerticalScrollBar = true;
	
	private Content content;
	
	private Collection<ScrollPaneContentItemsListener<T>> scrollPaneContentItemsListeners = Collections.synchronizedCollection(new ArrayList<ScrollPaneContentItemsListener<T>>());
	
	public ScrollPane(String background, float width, float height, IntRectangle centerClipping, ScrollBar scrollBar) throws IOException {
		this(background, width, height, centerClipping, 
				scrollBar.getOrientation() == Adjustable.HORIZONTAL ? scrollBar : null, 
						scrollBar.getOrientation() == Adjustable.VERTICAL ? scrollBar : null);
	}
			
	public ScrollPane(String background, float width, float height, IntRectangle centerClipping, ScrollBar horizontalScrollBar, ScrollBar verticalScrollBar) throws IOException {
		super(background, width, height, centerClipping);
		this.horizontalScrollBar = horizontalScrollBar;
		this.verticalScrollBar = verticalScrollBar;
		this.checkScrollBar();
		this.setupScrollBar();
		this.setupContent();
	}
	
	public ScrollPane(String background, float width, float height, IntOffset centerClipping, ScrollBar scrollBar) throws IOException {
		this(background, width, height, centerClipping, 
				scrollBar.getOrientation() == Adjustable.HORIZONTAL ? scrollBar : null, 
						scrollBar.getOrientation() == Adjustable.VERTICAL ? scrollBar : null);
	}
			
	public ScrollPane(String background, float width, float height, IntOffset centerClipping, ScrollBar horizontalScrollBar, ScrollBar verticalScrollBar) throws IOException {
		super(background, width, height, centerClipping);
		this.horizontalScrollBar = horizontalScrollBar;
		this.verticalScrollBar = verticalScrollBar;
		this.checkScrollBar();
		this.setupScrollBar();
		this.setupContent();
	}

	public ScrollPane(String background, float width, float height, ScrollBar scrollBar) throws IOException {
		this(background, width, height, 
				scrollBar.getOrientation() == Adjustable.HORIZONTAL ? scrollBar : null, 
						scrollBar.getOrientation() == Adjustable.VERTICAL ? scrollBar : null);
	}
	
	public ScrollPane(String background, float width, float height, ScrollBar horizontalScrollBar, ScrollBar verticalScrollBar) throws IOException {
		super(background, width, height);
		this.horizontalScrollBar = horizontalScrollBar;
		this.verticalScrollBar = verticalScrollBar;
		this.checkScrollBar();
		this.setupScrollBar();
		this.setupContent();
	}

	public ScrollPane(String background, IntRectangle textureClipping, float width, float height, ScrollBar scrollBar) throws IOException {
		this(background, textureClipping, width, height, 
				scrollBar.getOrientation() == Adjustable.HORIZONTAL ? scrollBar : null, 
						scrollBar.getOrientation() == Adjustable.VERTICAL ? scrollBar : null);
	}
	
	public ScrollPane(String background, IntRectangle textureClipping, float width, float height, ScrollBar horizontalScrollBar, ScrollBar verticalScrollBar) throws IOException {
		super(background, textureClipping, width, height);
		this.horizontalScrollBar = horizontalScrollBar;
		this.verticalScrollBar = verticalScrollBar;
		this.checkScrollBar();
		this.setupScrollBar();
		this.setupContent();
	}

	public ScrollPane(String background, IntRectangle textureClipping, float width, float height, IntRectangle centerClipping, ScrollBar scrollBar) throws IOException {
		this(background, textureClipping, width, height, centerClipping, 
				scrollBar.getOrientation() == Adjustable.HORIZONTAL ? scrollBar : null, 
						scrollBar.getOrientation() == Adjustable.VERTICAL ? scrollBar : null);
	}
	
	public ScrollPane(String background, IntRectangle textureClipping, float width, float height, IntRectangle centerClipping, ScrollBar horizontalScrollBar, ScrollBar verticalScrollBar)
			throws IOException {
		super(background, textureClipping, width, height, centerClipping);
		this.horizontalScrollBar = horizontalScrollBar;
		this.verticalScrollBar = verticalScrollBar;
		this.checkScrollBar();
		this.setupScrollBar();
		this.setupContent();
	}

	public ScrollPane(String background, IntRectangle textureClipping, float width, float height, IntOffset centerClipping, ScrollBar scrollBar) throws IOException {
		this(background, textureClipping, width, height, centerClipping, 
				scrollBar.getOrientation() == Adjustable.HORIZONTAL ? scrollBar : null, 
						scrollBar.getOrientation() == Adjustable.VERTICAL ? scrollBar : null);
	}
	
	public ScrollPane(String background, IntRectangle textureClipping, float width, float height, IntOffset centerClipping, ScrollBar horizontalScrollBar, ScrollBar verticalScrollBar)
			throws IOException {
		super(background, textureClipping, width, height, centerClipping);
		this.horizontalScrollBar = horizontalScrollBar;
		this.verticalScrollBar = verticalScrollBar;
		this.checkScrollBar();
		this.setupScrollBar();
		this.setupContent();
	}
	
	public ScrollPane(ObjectCount<Texture> background, float width, float height, IntRectangle centerClipping, ScrollBar scrollBar) throws IOException {
		this(background, width, height, centerClipping, 
				scrollBar.getOrientation() == Adjustable.HORIZONTAL ? scrollBar : null, 
						scrollBar.getOrientation() == Adjustable.VERTICAL ? scrollBar : null);
	}
			
	public ScrollPane(ObjectCount<Texture> background, float width, float height, IntRectangle centerClipping, ScrollBar horizontalScrollBar, ScrollBar verticalScrollBar) throws IOException {
		super(background, width, height, centerClipping);
		this.horizontalScrollBar = horizontalScrollBar;
		this.verticalScrollBar = verticalScrollBar;
		this.checkScrollBar();
		this.setupScrollBar();
		this.setupContent();
	}
	
	public ScrollPane(ObjectCount<Texture> background, float width, float height, IntOffset centerClipping, ScrollBar scrollBar) throws IOException {
		this(background, width, height, centerClipping, 
				scrollBar.getOrientation() == Adjustable.HORIZONTAL ? scrollBar : null, 
						scrollBar.getOrientation() == Adjustable.VERTICAL ? scrollBar : null);
	}
			
	public ScrollPane(ObjectCount<Texture> background, float width, float height, IntOffset centerClipping, ScrollBar horizontalScrollBar, ScrollBar verticalScrollBar) throws IOException {
		super(background, width, height, centerClipping);
		this.horizontalScrollBar = horizontalScrollBar;
		this.verticalScrollBar = verticalScrollBar;
		this.checkScrollBar();
		this.setupScrollBar();
		this.setupContent();
	}

	public ScrollPane(ObjectCount<Texture> background, float width, float height, ScrollBar scrollBar) throws IOException {
		this(background, width, height, 
				scrollBar.getOrientation() == Adjustable.HORIZONTAL ? scrollBar : null, 
						scrollBar.getOrientation() == Adjustable.VERTICAL ? scrollBar : null);
	}
	
	public ScrollPane(ObjectCount<Texture> background, float width, float height, ScrollBar horizontalScrollBar, ScrollBar verticalScrollBar) throws IOException {
		super(background, width, height);
		this.horizontalScrollBar = horizontalScrollBar;
		this.verticalScrollBar = verticalScrollBar;
		this.checkScrollBar();
		this.setupScrollBar();
		this.setupContent();
	}

	public ScrollPane(ObjectCount<Texture> background, IntRectangle textureClipping, float width, float height, ScrollBar scrollBar) throws IOException {
		this(background, textureClipping, width, height, 
				scrollBar.getOrientation() == Adjustable.HORIZONTAL ? scrollBar : null, 
						scrollBar.getOrientation() == Adjustable.VERTICAL ? scrollBar : null);
	}
	
	public ScrollPane(ObjectCount<Texture> background, IntRectangle textureClipping, float width, float height, ScrollBar horizontalScrollBar, ScrollBar verticalScrollBar) throws IOException {
		super(background, textureClipping, width, height);
		this.horizontalScrollBar = horizontalScrollBar;
		this.verticalScrollBar = verticalScrollBar;
		this.checkScrollBar();
		this.setupScrollBar();
		this.setupContent();
	}

	public ScrollPane(ObjectCount<Texture> background, IntRectangle textureClipping, float width, float height, IntRectangle centerClipping, ScrollBar scrollBar) throws IOException {
		this(background, textureClipping, width, height, centerClipping, 
				scrollBar.getOrientation() == Adjustable.HORIZONTAL ? scrollBar : null, 
						scrollBar.getOrientation() == Adjustable.VERTICAL ? scrollBar : null);
	}
	
	public ScrollPane(ObjectCount<Texture> background, IntRectangle textureClipping, float width, float height, IntRectangle centerClipping, ScrollBar horizontalScrollBar, ScrollBar verticalScrollBar)
			throws IOException {
		super(background, textureClipping, width, height, centerClipping);
		this.horizontalScrollBar = horizontalScrollBar;
		this.verticalScrollBar = verticalScrollBar;
		this.checkScrollBar();
		this.setupScrollBar();
		this.setupContent();
	}

	public ScrollPane(ObjectCount<Texture> background, IntRectangle textureClipping, float width, float height, IntOffset centerClipping, ScrollBar scrollBar) throws IOException {
		this(background, textureClipping, width, height, centerClipping, 
				scrollBar.getOrientation() == Adjustable.HORIZONTAL ? scrollBar : null, 
						scrollBar.getOrientation() == Adjustable.VERTICAL ? scrollBar : null);
	}
	
	public ScrollPane(ObjectCount<Texture> background, IntRectangle textureClipping, float width, float height, IntOffset centerClipping, ScrollBar horizontalScrollBar, ScrollBar verticalScrollBar)
			throws IOException {
		super(background, textureClipping, width, height, centerClipping);
		this.horizontalScrollBar = horizontalScrollBar;
		this.verticalScrollBar = verticalScrollBar;
		this.checkScrollBar();
		this.setupScrollBar();
		this.setupContent();
	}
	
	@Override
	protected void setup() {
		super.setup();
		content = createContent();
		add(getContent());
	}

	protected Content createContent() {
		return new Content(100, 100);
	}
	
	protected void checkScrollBar() {
		if(getHorizontalScrollBar() == null && getVerticalScrollBar() == null) {
			getUi().destroy();
			throw new IllegalArgumentException("必须存在horizontalScrollBar与verticalScrollBar其中一个参数");
		}
	}
	
	protected void setupScrollBar() {
		Rectangle rect = getViewRectangle();
		if(getHorizontalScrollBar() != null) {
			if(getVerticalScrollBar() != null) {
				getHorizontalScrollBar().position.setX(-getVerticalScrollBar().getWidth() / 2);
			}
			getHorizontalScrollBar().position.setY(rect.bottom + getHorizontalScrollBar().getHeight() / 2);
			getHorizontalScrollBar().addScrollBarListener(this);
			add(getHorizontalScrollBar());
		}
		if(getVerticalScrollBar() != null) {
			getVerticalScrollBar().position.setX(rect.right - getVerticalScrollBar().getWidth() / 2);
			if(getHorizontalScrollBar() != null) {
				getVerticalScrollBar().position.setY(getHorizontalScrollBar().getHeight() / 2);
			}
			getVerticalScrollBar().addScrollBarListener(this);
			add(getVerticalScrollBar());
		}
		//计算横向滚动条初始位置
		if(getHorizontalScrollBar() != null) {
			onScroll(getHorizontalScrollBar(), 
					getHorizontalScrollBar().getValue(), 
					getHorizontalScrollBar().getMin(), 
					getHorizontalScrollBar().getMax());
		}
		//计算纵向滚动条初始位置
		if(getVerticalScrollBar() != null) {
			onScroll(getVerticalScrollBar(), 
					getVerticalScrollBar().getValue(), 
					getVerticalScrollBar().getMin(), 
					getVerticalScrollBar().getMax());
		}
	}
	
	protected void computeScrollBarPosition() {
		Rectangle rect = getViewRectangle();
		if(getHorizontalScrollBar() != null && isShowHorizontalScrollBar()) {
			if(getVerticalScrollBar() != null) {
				getHorizontalScrollBar().position.setX(-getVerticalScrollBar().getWidth() / 2);
			}
			getHorizontalScrollBar().position.setY(rect.bottom + getHorizontalScrollBar().getHeight() / 2);
		}
		if(getVerticalScrollBar() != null && isShowVerticalScrollBar()) {
			getVerticalScrollBar().position.setX(rect.right - getVerticalScrollBar().getWidth() / 2);
			if(getHorizontalScrollBar() != null) {
				getVerticalScrollBar().position.setY(getHorizontalScrollBar().getHeight() / 2);
			}
		}
	}
	
	protected void setupContent() {
		computeContentViewSize();
		getContent().setContentWidth(getContent().getWidth());
		getContent().setContentHeight(getContent().getHeight());
	}
	
	protected void computeContentViewSize() {
		Rectangle viewer = this.getViewRectangle();
		float x = 0;
		float y = 0;
		float width = viewer.right - viewer.left;
		float height = viewer.top - viewer.bottom;
		if(this.isShowHorizontalScrollBar() && getHorizontalScrollBar() != null) {
			y += getHorizontalScrollBar().getHeight() / 2;
			height -= getHorizontalScrollBar().getHeight();
		}
		if(this.isShowVerticalScrollBar() && getVerticalScrollBar() != null) {
			x -= getVerticalScrollBar().getWidth() / 2;
			width -= getVerticalScrollBar().getWidth();
		}
		getContent().setWidth(width);
		getContent().setHeight(height);
		getContent().position.set(x, y);
	}

	@Override
	public void onScroll(ScrollBar scrollBar, int value, int min, int max) {
		int left = value - min;
		int length = max - min;
		Rectangle viewer = getContentViewRectangle();
		if(scrollBar == getHorizontalScrollBar()) {
			float viewWidth = viewer.right - viewer.left; 
			getContent().getScrollOffset().setX(- (left * (getContentWidth() - viewWidth) / length));
		}
		if(scrollBar == getVerticalScrollBar()) {
			float viewHeight = viewer.top - viewer.bottom; 
			getContent().getScrollOffset().setY(left * (getContentHeight() - viewHeight) / length);
		}
		getContent().setAutoVisible(viewer);
	}
	
	public synchronized void addContentItem(int index, T item) {
		getContent().add(index, item);
		computeContentSize();
	}
	
	public synchronized boolean addContentItem(T item) {
		boolean result = getContent().add(item);
		if(result) {
			computeContentSize();
		}
		return result;
	}
	
	public synchronized boolean addAllContentItem(Collection<T> items) {
		boolean result = getContent().addAll(items);
		if(result) {
			computeContentSize();
		}
		return result;
	}
	
	public synchronized boolean addAllContentItem(int index, Collection<T> items) {
		boolean result = getContent().addAll(index, items);
		if(result) {
			computeContentSize();
		}
		return result;
	}
	
	public synchronized boolean removeContentItem(T item) {
		boolean result = getContent().remove(item);
		if(result) {
			computeContentSize();
		}
		return result;
	}
	
	@SuppressWarnings("unchecked")
	public synchronized T removeContentItem(int index) {
		T result = (T) getContent().remove(index);
		computeContentSize();
		return result;
	}
	
	public synchronized boolean removeAllContentItems(Collection<T> items) {
		boolean result = getContent().removeAll(items);
		if(result) {
			computeContentSize();
		}
		return result;
	}
	
	public synchronized void clearContentItems() {
		getContent().clear();
		computeContentSize();
	}
	
	public int contentItemsSize() {
		return getContent().size();
	}
	
	protected Content getContent() {
		return content;
	}
	
	public void scroll(T item) {
		if(getContent().contains(item)) {
			Rectangle viewer = getContentViewRectangle();
			Rectangle rect = item.getRectangleFromParent();
			if(getHorizontalScrollBar() != null) {
				if(rect.left + getContent().getScrollOffset().getX() < viewer.left) {
					float distance = rect.left - viewer.left;
					float width = getContentWidth() - (viewer.right - viewer.left);
					int value = (int) (distance  * (getHorizontalScrollBar().getMax() - getHorizontalScrollBar().getMin()) / width);
					getHorizontalScrollBar().scroll(value);
				} else if(rect.right + getContent().getScrollOffset().getX() > viewer.right) {
					float distance = rect.right - viewer.right;
					float width = getContentWidth() - (viewer.right - viewer.left);
					int value = (int) (distance  * (getHorizontalScrollBar().getMax() - getHorizontalScrollBar().getMin()) / width);
					getHorizontalScrollBar().scroll(value);
				}
			}
			if(getVerticalScrollBar() != null) {
				if(rect.top + getContent().getScrollOffset().getY() > viewer.top) {
					float distance = viewer.top - rect.top;
					float height = getContentHeight() - (viewer.top - viewer.bottom);
					int value = (int) (distance  * (getVerticalScrollBar().getMax() - getVerticalScrollBar().getMin()) / height);
					getVerticalScrollBar().scroll(value);
				} else if(rect.bottom + getContent().getScrollOffset().getY() < viewer.bottom) {
					float distance = viewer.bottom - rect.bottom;
					float height = getContentHeight() - (viewer.top - viewer.bottom);
					int value = (int) (distance  * (getVerticalScrollBar().getMax() - getVerticalScrollBar().getMin()) / height);
					getVerticalScrollBar().scroll(value);
				}
			}
		}
	}
	
	public Rectangle getContentViewRectangle() {
		return getContent().getViewRectangle();
	}
	
	@SuppressWarnings("unchecked")
	protected void computeContentSize() {
		//触发监听调整items坐标
		triggerScrollPaneContentItemsListeners();
		//重新内容计算尺寸
		Rectangle viewer = getContentViewRectangle();
		float right = viewer.right;
		float bottom = viewer.bottom;
		Rectangle box = null;
		for(dev.ece.core.sprite.Component<?, ?> item: getContent()) {
			box = ((T) item).getRectangleFromParent();
			right = Math.max(right, box.right);
			bottom = Math.min(bottom, box.bottom);
		}
		float oldContentWidth = getContentWidth();
		float oldContentHeight = getContentHeight();
		
		setContentWidth(right - viewer.left);
		setContentHeight(viewer.top - bottom);
		float viewerWidth = viewer.right - viewer.left;
		if(getContentWidth() > viewerWidth && oldContentWidth > viewerWidth) {
			//重新计算横向滚动条位置
			if(oldContentWidth != getContentWidth() && getHorizontalScrollBar() != null) {
				int num = getHorizontalScrollBar().getValue() - getHorizontalScrollBar().getMin();
				int length = getHorizontalScrollBar().getMax() - getHorizontalScrollBar().getMin();
				float offset = num * (oldContentWidth - viewerWidth) / length;
				int value = (int) (offset / (getContentWidth() - viewerWidth) * length);
				getHorizontalScrollBar().scroll(value);
			}
		} else {
			if(getHorizontalScrollBar() != null) {
				getHorizontalScrollBar().scroll(0);
			}
		}
		float viewerHeight = viewer.top - viewer.bottom;
		if(getContentHeight() > viewerHeight && oldContentHeight > viewerHeight) {
			//重新计算纵向滚动条位置
			if(oldContentHeight != getContentHeight() && getVerticalScrollBar() != null) {
				int num = getVerticalScrollBar().getValue() - getVerticalScrollBar().getMin();
				int length = getVerticalScrollBar().getMax() - getVerticalScrollBar().getMin();
				float offset = num * (oldContentHeight - viewerHeight) / length;
				int value = (int) (offset / (getContentHeight() - viewerHeight) * length);
				getVerticalScrollBar().scroll(value);
			}
		} else {
			if(getVerticalScrollBar() != null) {
				getVerticalScrollBar().scroll(0);
			}
		}
	}
	
	public boolean isShowHorizontalScrollBar() {
		return showHorizontalScrollBar;
	}

	public void setShowHorizontalScrollBar(boolean showHorizontalScrollBar) {
		this.showHorizontalScrollBar = showHorizontalScrollBar;
		if(getHorizontalScrollBar() != null) {
			if(isShowHorizontalScrollBar()) {
				if(!this.contains(getHorizontalScrollBar())) {
					this.add(getHorizontalScrollBar());
				}
				setupScrollBar();
			} else {
				this.remove(getHorizontalScrollBar());
			}
			this.computeContentViewSize();
			this.computeContentSize();
		}
	}

	public boolean isShowVerticalScrollBar() {
		return showVerticalScrollBar;
	}

	public void setShowVerticalScrollBar(boolean showVerticalScrollBar) {
		this.showVerticalScrollBar = showVerticalScrollBar;
		if(getVerticalScrollBar() != null) {
			if(isShowVerticalScrollBar()) {
				if(!this.contains(getVerticalScrollBar())) {
					this.add(getVerticalScrollBar());
				}
				setupScrollBar();
			} else {
				this.remove(getVerticalScrollBar());
			}
			this.computeContentViewSize();
			this.computeContentSize();
		}
	}

	public float getContentWidth() {
		return getContent().getContentWidth();
	}

	protected void setContentWidth(float contentWidth) {
		getContent().setContentWidth(contentWidth);
		if(getHorizontalScrollBar() != null) {
			Rectangle rect = getContentViewRectangle();
			getHorizontalScrollBar().getHandlerButton().setDisabled(!(getContentWidth() > rect.right - rect.left));
		}
	}

	public float getContentHeight() {
		return getContent().getContentHeight();
	}

	protected void setContentHeight(float contentHeight) {
		getContent().setContentHeight(contentHeight);
		if(getVerticalScrollBar() != null) {
			Rectangle rect = getContentViewRectangle();
			getVerticalScrollBar().getHandlerButton().setDisabled(!(getContentHeight() > rect.top - rect.bottom));
		}
	}

	public ScrollBar getHorizontalScrollBar() {
		return horizontalScrollBar;
	}

	public ScrollBar getVerticalScrollBar() {
		return verticalScrollBar;
	}
	
	protected Collection<ScrollPaneContentItemsListener<T>> getScrollPaneContentItemsListeners() {
		return scrollPaneContentItemsListeners;
	}
	
	@SuppressWarnings("unchecked")
	protected void triggerScrollPaneContentItemsListeners() {
		for(ScrollPaneContentItemsListener<T> scrollPaneContentItemsListener: getScrollPaneContentItemsListeners()) {
			Vector<T> items = new Vector<T>();
			for(Object o:getContent()) {
				items.add((T) o);
			}
			scrollPaneContentItemsListener.onContentItemChanged(this, items);
		}
	}

	public void addScrollPaneContentItemsListener(ScrollPaneContentItemsListener<T> scrollPaneContentItemsListener) {
		if(!getScrollPaneContentItemsListeners().contains(scrollPaneContentItemsListener)) {
			getScrollPaneContentItemsListeners().add(scrollPaneContentItemsListener);
		}
	}
	
	public boolean containsScrollPaneContentItemsListener(ScrollPaneContentItemsListener<T> scrollPaneContentItemsListener) {
		return getScrollPaneContentItemsListeners().contains(scrollPaneContentItemsListener);
	}
	
	public void removeScrollPaneContentItemsListener(ScrollPaneContentItemsListener<T> scrollPaneContentItemsListener) {
		getScrollPaneContentItemsListeners().remove(scrollPaneContentItemsListener);
	}

	public int scrollPaneContentItemsListenersLength() {
		return getScrollPaneContentItemsListeners().size();
	}
	
	@Override
	public void setPadding(IntRectangle padding) {
		super.setPadding(padding);
		this.computeScrollBarPosition();
		this.computeContentViewSize();
		this.computeContentSize();
	}
	
	@Override
	public void clearup() {
		super.clearup();
		getScrollPaneContentItemsListeners().clear();
	}
	
}

class Content extends Container {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1592058091035613602L;

	private Vector2f scrollOffset = new Vector2f();
	
	private float contentWidth;
	
	private float contentHeight;
	
	public Content(float width, float height) {
		super(width, height);
	}
	
	protected void setAutoVisible(Rectangle viewer) {
		Vector2f offset = getScrollOffset();
		Rectangle box = null;
		ContentItem item = null;
		for(Object obj: this) {
			item = (ContentItem) obj;
			box = item.getRectangleFromParent();
			box.left += offset.getX();
			box.right += offset.getX();
			box.top += offset.getY();
			box.bottom += offset.getY();
			item.setAutoVisible(box.left < viewer.right && box.right > viewer.left && box.bottom < viewer.top && box.top > viewer.bottom);
		}
	}
	
	@Override
	protected void renderChildren(Camera camera) {
		GLUtils.getModelViewMatrix().translate(getScrollOffset().getX(), getScrollOffset().getY(), 0);
		glPushScissor();
		super.renderChildren(camera);
		glPopScissor();
	}

	@Override
	public boolean isMouseInComponent(float x, float y) {
		Vector2f absolutePosition = this.getSuperAbsolutePosition();
		return Math.abs(x - absolutePosition.getX()) <= this.getWidth() / 2 &&
				Math.abs(y - absolutePosition.getY()) <= this.getHeight() / 2;
	}

	@Override
	public Rectangle getAbsoluteViewRectangle() {
		Rectangle rect = this.getViewRectangle();
		Vector2f position = getSuperAbsolutePosition();
		rect.left += position.getX();
		rect.right += position.getX();
		rect.top += position.getY();
		rect.bottom += position.getY();
		return rect;
	}

	@Override
	public Rectangle getAbsoluteRectangle() {
		Rectangle rect = getRectangle();
		Vector2f position = getSuperAbsolutePosition();
		rect.left += position.getX();
		rect.right += position.getX();
		rect.top += position.getY();
		rect.bottom += position.getY();
		return rect;
	}
	
	public Vector2f getSuperAbsolutePosition() {
		return super.getAbsolutePosition();
	}
	
	@Override
	public Vector2f getAbsolutePosition() {
		Vector2f result = getSuperAbsolutePosition();
		result.add(getScrollOffset());
		return result;
	}
	
	@Override
	public Rectangle getViewRectangle() {
		return getRectangle();
	}

	protected Vector2f getScrollOffset() {
		return scrollOffset;
	}

	protected float getContentWidth() {
		return contentWidth;
	}

	protected void setContentWidth(float contentWidth) {
		this.contentWidth = contentWidth;
	}

	protected float getContentHeight() {
		return contentHeight;
	}

	protected void setContentHeight(float contentHeight) {
		this.contentHeight = contentHeight;
	}

}
